<?php

declare (strict_types=1);
/**
 * @copyright 深圳市易果网络科技有限公司
 * @version 1.0.0
 * @link https://dayiguo.com
 */

namespace App\Dao;

use App\Exception\CustomException;
use App\Job\IntegralJob;
use App\Kernel\Traits\DaoTrait;
use App\Kernel\Util\UserJwtInstance;
use App\Model\IntegralDetail;
use App\Model\Order;
use App\Model\Goods;
use App\Model\GoodsSku;
use App\Model\OrderItem;

use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
/**
 * class
 *
 * @author 谢声强(861167322@qq.com)
 * @package App\Dao
 */
class OrderDao extends Dao
{
    /**
     * 订单状态：待支付
     *
     * @var int
     */
    const STATUS_UNPAID = 0;

    /**
     * 订单状态：已支付
     *
     * @var int
     */
    const STATUS_PAID = 1;

    /**
     * 订单状态：已发货
     *
     * @var int
     */
    const STATUS_DELIVERY = 2;

    /**
     * 订单状态：已完成
     *
     * @var int
     */
    const STATUS_RECEIVED = 3;

    /**
     * 订单状态：退款中
     *
     * @var int
     */
    const STATUS_IN_REFUND = 4;

    /**
     * 订单状态：已退款
     *
     * @var int
     */
    const STATUS_REFUND = 5;

    /**
     * 订单状态：已取消
     *
     * @var int
     */
    const STATUS_CANCEL = 6;

    /**
     * 取消订单限制状态
     *
     * @var array
     */
    const CANCEL_ORDER = [self::STATUS_PAID, self::STATUS_CANCEL, self::STATUS_DELIVERY, self::STATUS_RECEIVED, self::STATUS_IN_REFUND, self::STATUS_REFUND];

    /**
     * 确定收货限制状态
     *
     * @var array
     */
    const SURE_ORDER = [self::STATUS_UNPAID, self::STATUS_CANCEL, self::STATUS_RECEIVED, self::STATUS_IN_REFUND, self::STATUS_REFUND];

    /**
     * 积分类型：收入
     *
     * @var int
     */
    const INTEGRAL_INCOME = 1;

    /**
     * 积分类型：支出
     *
     * @var int
     */
    const INTEGRAL_EXPEND = 2;

    /**
     * 积分状态：消费
     *
     * @var int
     */
    const INTEGRAL_STATUS_CONSUME = 1;

    /**
     * 积分状态：分润
     *
     * @var int
     */
    const INTEGRAL_STATUS_RETAIL  = 2;

    use DaoTrait;

    /**
     * @inheritDoc
     */
    public function model(): string
    {
        return Order::class;
    }

    /**
     * 根据条件获取收藏个数
     *
     * @param array $map
     * @return int
     */
    public function count(array $map = [])
    {
        return Order::query()->where(function($query) use ($map) { return queryWhere($query, $map); })->count();
    }

    /**
     *通过订单ID查询订单
     */
    public function getFirstOrder( $order_id )
    {
        return Order::query()->where('id', $order_id)->first();
    }

    /**
     * 创建订单
     *
     * @param array $order
     * @param array $order_item
     */
    public function createOrder(array $order, array $order_item)
    {
        Db::beginTransaction();
        try {
            // 创建订单
            if (!self::makeModel()->create($order)) {
                throw new CustomException('ORDER.CREATE_FAIL');
            }

            // 判断积分是否足够
            if ($order['integral'] > 0) {
                $user = UserJwtInstance::instance()->build()->getUser();
                if ($user->integral < $order['integral']) {
                    $this->driver->push(new IntegralJob( $user->id ));
                    throw new CustomException('USER.INTEGER_NOT_ENOUGH');
                }

                // 扣除积分
                $user->integral = $user->integral - $order['integral'];
                if (!$user->save()) {
                    $this->driver->push(new IntegralJob( $user->id ));
                    throw new CustomException('USER.INTEGER_PAY_FAIL');
                }

                // 写入积分记录
                IntegralDetail::query()->create([
                    'user_id' => $user->id,
                    'status' => self::INTEGRAL_STATUS_CONSUME,
                    'type' => self::INTEGRAL_EXPEND,
                    'num' => -$order['integral'],
                    'remark' => '兑换商品',
                    'order_no' => $order['order_no']
                ]);
                $this->driver->push(new IntegralJob( $user->id ));
            }
            // 创建订单items
            if (!OrderItem::query()->insert($order_item)) {
                throw new CustomException('ORDER.CREATE_ITEM_FAIL');
            }

            // 扣除SKU库存及商品库存
            foreach ($order_item as $item) {
                $goods_stock = Goods::query()->where('id', $item['goods_id'])->where('stock', '>', $item['num'])->decrement('stock', $item['num']);
                if (!$goods_stock) {
                    throw new CustomException('GOODS.STOCK_NOT_ENOUGH');
                }
                $sku_stock = GoodsSku::query()->where('id', $item['sku_id'])->where('stock', '>', $item['num'])->decrement('stock', $item['num']);
                if (!$sku_stock) {
                    throw new CustomException('GOODS.STOCK_NOT_ENOUGH');
                }
            }

            Db::commit();
        }
        catch (CustomException $e) {
            Db::rollBack();
            $this->error($e->getMessage());
        }
        catch (\Exception $e) {
            Db::rollBack();
            $this->error('COMMON.SYSTEM_ERROR');
        }
    }

    /**
     * 获取用户订单
     *
     * @param array $map
     * @return mixed
     */
    public function  get(array $map = [])
    {
        return Order::query()
            ->with('items:id,order_no,sku_picture,goods_name,price,num,sku_name')
            ->where(function ($query) use ($map) {
                return queryWhere($query, $map);
            })
            ->where('user_id', uid())
            ->orderByDesc('created_at')
            ->select('id', 'order_no', 'total_price','status')
            ->paginate(10);
    }

    /**
     * 订单详情
     *
     * @param int $order_id
     * @return mixed
     */
    public function detail(int $order_id)
    {
        $uid = uid();
        return Order::query()
            ->with(['items.goods', 'items.goodsSku'])
            ->where('user_id', $uid)
            ->where('id', $order_id)
            ->first();
    }


    /**
     * 通过条件获取用户单个订单记录
     *
     * @param array $map
     * @return mixed
     */
    public function getOrderByMap(array $map = [])
    {
        return Order::query()
            ->where(function ($query) use ($map) {
                return queryWhere($query, $map);
            })
        ->first();
    }
}